using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using TXLooker.Common;
using TXLooker.Common.Core;

namespace TXLooker.Core
{
    internal class ServerProvider : SelfUpdater
    {
        private ServerProvider()
        { }
        public ServerProvider( Uri serverUri ) : this()
        {
            this.ServerUri = serverUri;
        }
        public ServerProvider( string serverUri ) : this( new Uri(serverUri) )
        { }

        /// <summary>
        /// 
        /// </summary>
        public bool UseProjectFilter
        {
            get { return this.m_bUseProjectFilter;  }
            set { this.m_bUseProjectFilter = value; }
        }
        private bool m_bUseProjectFilter = false;

        /// <summary>
        /// Project Filter
        /// </summary>
        public IEnumerable<Uri> ProcessProjects
        {
            get 
            {
                lock( this.m_useProjects )
                {
                    foreach( Uri item in this.m_useProjects )
                        yield return item;
                }
            }
        }
        public void SetProcessProjectList( IEnumerable<string> uries )
        {
            List<Uri> items = new List<Uri>();

            foreach( string item in uries )
            {
                try
                {
                    items.Add( new Uri(item) );
                }
                catch( System.Exception ex )
                {
                    Debug.WriteLine( ex.ToString() );
                }
            }

            this.SetProcessProjectList( items );
        }
        public void SetProcessProjectList( IEnumerable<Uri> uries )
        {
            lock( this.m_projectMAP )
            {
                this.m_useProjects.Clear();
                this.m_useProjects.AddRange( uries );
            }
        }
        private List<Uri> m_useProjects = new List<Uri>();

        protected override void UpdateData()
        {
            try
            {
                ICommonStructureService structure = this.CommonServerStructure;
                if( structure == null ) return;

                Dictionary<Uri, ProjectProvider> prevState = new Dictionary<Uri, ProjectProvider>();
                lock( this.m_projectMAP )
                {
                    foreach( Uri key in this.m_projectMAP.Keys )
                        prevState.Add( key, this.m_projectMAP[key] );
                }

                List<ProjectProvider> addProjects = new List<ProjectProvider>();

                foreach( ProjectInfo item in structure.ListAllProjects() )
                {
                    Uri uri = new Uri( item.Uri );

                    //check
                    if( this.UseProjectFilter )
                    {
                        if( !this.m_useProjects.Contains(uri) )
                        {
                            if( this.m_projectMAP.ContainsKey(uri) ) this.m_projectMAP.Remove(uri);
                            continue;
                        }
                    }

                    switch( item.Status )
                    {
                        case ProjectState.New:
                        case ProjectState.WellFormed:
                            {
                                if( !prevState.ContainsKey(uri) )
                                {
                                    ProjectProvider provider = new ProjectProvider( this, item );
                                    addProjects.Add(provider);
                                }
                                else
                                {
                                    prevState.Remove(uri);
                                }
                            }
                            break;
                        case ProjectState.Deleting:
                            {
                                if( prevState.ContainsKey(uri) ) this.m_projectMAP.Remove( uri );
                            }
                            break;
                    }

                }

                if( prevState.Values.Count != 0 )
                {
                    try
                    {
                        this.RaisePreRemoveProjects( prevState.Values );
                    }
                    catch( System.Exception ex )
                    {
                        Debug.WriteLine( ex.ToString() );
                    }

                    lock( this.m_projectMAP )
                    {
                        foreach( ProjectProvider item in prevState.Values )
                            this.m_projectMAP.Remove( item.ProjectUri );
                    }
                }
                if( addProjects.Count != 0 )
                {
                    lock( this.m_projectMAP )
                    {
                        foreach( ProjectProvider item in addProjects )
                            this.m_projectMAP.Add( item.ProjectUri, item );
                    }

                    try
                    {
                        this.RaiseNewProjects( addProjects );
                    }
                    catch( System.Exception ex )
                    {
                        Debug.WriteLine( ex.ToString() );
                    }
                }
            }
            catch( System.Exception ex )
            { 
                Debug.WriteLine( ex.ToString() );
            }
        }

        public string ServerName
        {
            get 
            {
                if( this.Server != null ) 
                    return this.Server.Name;

                if( this.m_serverName == null && this.ServerUri != null )
                {
                    Regex rg = new Regex( @"^http(s)?://(?<name>.*?)\s*(:\s*?\d+?)?\s*?$" );
                    Match m = rg.Match( this.ServerUri.ToString() );

                    if( m.Success )
                        this.m_serverName = m.Groups["name"].Value.Trim();
                }
                return this.m_serverName;  
            }
        }
        private string m_serverName = null;

        public Uri ServerUri
        {
            get { return this.m_serverUri; }
            protected set
            {
                this.m_serverUri = value;
            }
        }
        private Uri m_serverUri = null;

        public TeamFoundationServer Server
        {
            get
            {
                if( this.m_tfServer == null && this.ServerUri != null )
                    this.m_tfServer = new TeamFoundationServer( this.ServerUri.ToString() );

                return this.m_tfServer;
            }
        }
        private TeamFoundationServer m_tfServer = null;

        public IEnumerable<ProjectProvider> Projects
        {
            get 
            {
                lock( this.m_projectMAP )
                {
                    foreach( ProjectProvider item in this.m_projectMAP.Values )
                        yield return item;
                }
            }
        }
        private Dictionary<Uri, ProjectProvider> m_projectMAP = new Dictionary<Uri, ProjectProvider>();

        #region event NewProjects

        public event TFEventHandler<IEnumerable<ProjectProvider>> NewProjects
        {
            add    { lock( this.m_syncNewProjects ) { this.m_OnNewProjectsEH += value; } }
            remove { lock( this.m_syncNewProjects ) { this.m_OnNewProjectsEH -= value; } }
        }
        private TFEventHandler<IEnumerable<ProjectProvider>> m_OnNewProjectsEH = null;

        private readonly object m_syncNewProjects = new object();

        private void RaiseNewProjects( IEnumerable<ProjectProvider> projects )
        {
            CommonGlobal.RaiseEventHandler( this.m_OnNewProjectsEH, new object[] { this, projects }, m_syncNewProjects );
        }

        #endregion event NewProjects

        #region event PreRemoveProjects

        public event TFEventHandler<IEnumerable<ProjectProvider>> PreRemoveProjects
        {
            add    { lock( this.m_syncDeleteProjects ) { this.m_OnPreRemoveProjectsEH += value; } }
            remove { lock( this.m_syncDeleteProjects ) { this.m_OnPreRemoveProjectsEH -= value; } }
        }
        private TFEventHandler<IEnumerable<ProjectProvider>> m_OnPreRemoveProjectsEH = null;

        private readonly object m_syncDeleteProjects = new object();

        private void RaisePreRemoveProjects( IEnumerable<ProjectProvider> projects)
        {
            CommonGlobal.RaiseEventHandler( this.m_OnPreRemoveProjectsEH, new object[] { this, projects }, m_syncDeleteProjects );
        }

        #endregion event PreRemoveProjects

        public ICommonStructureService CommonServerStructure
        {
            get 
            {
                ICommonStructureService structure = null;

                try
                {
                    TeamFoundationServer server = this.Server;

                    if( server != null )
                        structure = GetCommonServerStructure( server );
                }
                catch
                { }

                return structure;
            }
        }
        public static ICommonStructureService GetCommonServerStructure( TeamFoundationServer server )
        {
            ICommonStructureService service = null;

            try
            {
                service = server.GetService(typeof(ICommonStructureService)) as ICommonStructureService;
            }
            catch( System.Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }

            return service;
        }
        public static ICommonStructureService GetCommonServerStructure( string uri )
        {
            TeamFoundationServer server = new TeamFoundationServer(uri);
            return GetCommonServerStructure( server );
        }
        public static ICommonStructureService GetCommonServerStructure( Uri uri )
        {
            return GetCommonServerStructure( uri.ToString() );
        }

    }
}
